Git Kata 3: Merging
Learn about merging branches with divergent histories.
Merging is essentially the opposite of branching. Branches allow changes in a repository to be separated. Merging is the process of combining work that’s separated between branches.
Step 1: Merge changes between branches#
The command to merge changes is given below.
The output will be something like this:
Command's Parameters
Command / Parameter | Description |
| This applies the changes from one branch to another branch. |
| This is the branch from which we take commits and apply them to the current branch. |
The git merge command replays the changes from another branch on the current branch. Git will attempt to combine the commits from the source branch to the current branch. The result of the merge operation depends on the differences (if there are any) between the branches. The output of this command is:
Output
Message | Meaning |
"Updating c70b36e..1e19013" | This is the abbreviated source and the target commit hashes. |
"Fast-forward" | This is the merge strategy used to merge the source and target branches. |
"storelist.txt | 4++--" | These are the files affected by the merge and the lines that were modified. |
"1 file changed, 2 insertions(+), 2 deletions(-)" | This is a summary of the files changed and the modifications made. |
The previous step made a modification to storelist.txt in newbranch. The git merge newbranch command instructs Git to take the changes from newbranch and apply them to the current branch.
Git has several methods, called merge strategies, it can use to determine how to merge changes. This execution of Git merge uses the fast-forward strategy.
The main branch had no commits on it since the newbranch commit was added. Git was able to merge them efficiently by simply moving the HEAD and main refs to point to the latest commit in the commit history. When Git executes a fast-forward merge, only the refs are updated, so no new commits are necessary. Git merged the changes by updating the HEAD and main refs to point to the commit in newbranch. The next step will demonstrate merging where different versions of the same file exist in both branches.
Switch back to the text editor and reload the file.
The merge operation has updated storelist.txt in the working directory, applying the changes made in newbranch to the current branch, main. The “First line last” commit from newbranch has been applied to the main branch.
Step 2: Merge branches with divergent histories#
To append the text in the file and save:
- Add
(I love yogurt!)to the second line. - Save the changes.
The next several steps will demonstrate merging two branches with differing versions of the same file. This step makes the first change to storelist.txt while main is the current branch.
The command to commit the change to the repository is given below.
When we execute the command above, the output will be something like this:
Command's Parameters
Command / Parameter | Description |
| This creates a new commit in the current branch. |
| This stages all the modified files prior to the commit. |
| This sets a commit message on the command line. |
| This is the commit message. |
This step commits the change just made to storelist.txt in the main branch.
The command to witch to newbranch is given below.
The result will be something like this:
Command's Parameters
Command / Parameter | Description |
| This checks out a commit or switches to a branch. |
| This is the branch to be checked out. |
This step checks out newbranch.
To append the text in the file and save:
- Return to the text editor and reload the file.
- Add
(lowfat please)toMoo Milk. - Enter “Ctrl”+“S” to save.
This step makes a change on newbranch to a different line than the one changed in the main branch.
The command to commit the change to the repository is given below.
After the execution of the above command, the output will be something like this:
Command's Parameters
Command / Parameter | Description |
| This creates a new commit in the current branch. |
| This stages all the modified files prior to the commit. |
| This sets a commit message on the command line. |
| This is the commit message. |
This step commits the change made to the Moo Milk line.
The output of this command is:
Output
Message | Meaning |
"newbranch [ec8be18] Lowfat milk]" | This is the branch to which the commit was applied, the abbreviated hash of the commit, and the commit message |
"1 file changed, 1 insertion(+), 1 deletion(-)" | This is the number of files changed and lines inserted and deleted |
The updated visualization shows a truly divergent commit history. There are now two different versions of storelist.txt: one version in main and a different version in newbranch. The HEAD ref points to the commit in newbranch because it’s the most recent commit, and newbranch is the current branch.
The command to switch to main is given below.
The output of this command will be something like this:
Command's Parameters
Command / Parameter | Description |
| This checks out a commit or switches to a branch. |
| This is the branch to be checked out. |
This step uses git checkout to switch back to the main branch.
The command to display the differences between main and newbranch is given below:
After the execution of the above command, the output will be something like this:
Command's Parameters
Command / Parameter | Description |
| This displays the difference between objects, including commits, branches, the working tree, and index. |
| This execution of git diff indicates a branch, |
The git diff command is used to compare two objects. This step uses git diff to view the differences between the main branch and newbranch. git diff can be used to view the differences in branches when preparing for a merge.
The text-based format of the git diff command shows differences between the two compared objects. When comparing two branches, as this execution does, all the differences are listed. If there were more than one file with differences in the repository, they would be included in the output.
The output of git diff is designed to be machine-readable so that it can be fed into other commands and programs. Graphical diff tools present a more readable visual difference report. It’s possible and useful to learn to read this format.
The output of the command is:
Output
Message | Meaning |
"diff --git a/storelist.txt b/storelist.txt" | This is the header, indicating that the output includes a “version a” and “version b” of |
"index 694789f..166a8e7 100644" | This line indicates the hashes of the two files. The first hash is the “a” version, the second hash is the “b” version. The 100644 code details the type and permissions of the file. |
"--- a/storelist.txt" | This is the “from” version. It's the version that was modified first. The differences in this version are prepended in the output with the minus (-) sign and are colored red. |
"+++ b/storelist.txt" | This is the “to” version. The differences in this version are prepended in the output with the plus (+) sign and are colored green. |
"@@ -1,9 +1,9 @@" | This line indicates a difference hunk.
The remaining lines indicate the lines present in one version and not in the other. |
"-Yummy Yogurt" | This line is in the “from” or “a” version, indicated by the minus (-) sign. |
"+Yummy Yogurt (I love yogurt!)" | This line is in the “from” or “a” version, indicated by the minus (-) sign. |
"-Moo Milk (lowfat please)" | This line is in the “from” or “a” version, indicated by the minus (-) sign. |
"+Moo Milk" | This line is in the “to” or “b” version, indicated by the plus (+) sign. |
This output displays the differences in storelist.txt between the main and newbranch branches. With practice, we can learn to use this information to predict the results of a merge. Graphical tools are also available to display the differences visually, which makes that process easier.
The commands to merge the commits on newbranch to main are given below.
- Click “Ctrl”+“O.”
- Click “Enter.”
- Click “Ctrl”+“X.”
- View
storelist.txtin the editor. - Reload to see the changes.
The output will be something like this:
Commands
Command / Parameter | Description |
| This applies changes from one branch to another branch. |
| This is the branch from which we take commits and apply them to the current branch. |
| This saves and exits the nano editor, saving the commit message of the merge commit. |
This step creates a merge using the same command as in the previous step. However, the results of this merge are quite different due to the fact that it’s not a fast-forward merge.
The commit histories of main and newbranch are different in this case, so Git cannot perform a fast-forward merge. Git must perform a three-way merge. A three-way merge takes two commits and combines them together in a third commit: a merge commit. Merge commits are different from the commits we’ve seen so far in that they have two (or more) parents instead of one.
The default merge strategy, in this case, is called recursive. This execution of the Git merge resulted in an auto-merge. The Git merge algorithm has some smarts built into it so that Git can merge automatically whenever possible.
The recursive merge strategy favors the current branch by default (known as the ours option). Git assumes that we want the current branch, main, to take priority when merging. The differences in storelist.txt are on different lines, so Git can infer the result of the merge. The next kata will demonstrate a case where Git can’t guess what we want, so the conflicts must be resolved by hand.
The output of this command is:
Output
Message | Meaning |
"Auto-merging storelist.txt" | This indicates that Git was able to merge the branches automatically. |
"Merge made by the ‘recursive’ strategy" | This indicates the strategy used to perform the merge. |
"storelist.txt | 2 +-" | This is a list of the files affected and the number of lines modified. |
"1 file changed, 1 insertion(+), 1 deletion(-)" | This is a summary of the changes that were made in the merge. |
Note: We can refer to the output from the previous
git diffcommand to track the changes that are applied by the merge:
-Moo Milk (lowfat please): This line is in the “from” version. It will be present in the merge result because there’s no conflicting change in themainbranch version. This is the1 insertion(+)from the output.
+Moo Milk: This line is in the “to” version in themainbranch. This line hasn’t changed in themainbranch since the change innewbranch, so Git applies the other version. This is the“1 deletion(-)”from the output.
Note: The latest commit is the merge commit created by the merge. Merge commits have at least two parents.
Practice commands#
We’ve given a terminal and a table containing a list of commands discussed in this lesson. Try out these commands after running the terminal and check out the results!
Commands
Step | Command |
This merges the changes from |
|
|
|
This commits the change to the repository, setting the commit comment from the command line. |
|
This switches to |
|
This appends the text “(lowfat please)” to the “Moo Milk” line in the text editor and saves the file. |
|
This commits the change to the repository, setting the commit comment from the command line. |
|
This switches to |
|
This displays the differences between |
|
This merges the commits on |
|
This views |
|
Git Kata 2: Branches
Git Kata 4: Merge Conflicts